#pragma once

#include <logger/stream.hpp>

#include <engine.core/math.hpp>
#include <engine.core/System.hpp>
#include <engine.core/quad.hpp>

#include <engine.video/Device.hpp>
#include <engine.input/Device.hpp>

#include "StyleDefinition.hpp"
#include "Desktop.hpp"




namespace Engine
{
	namespace Ui
	{
		class ENGINE_UI_API System
			: public Engine::System
		{
		public:

			friend class EngineImpl;

			SHARED(System);

		protected:

			System(const EngineInfo& info, Video::Device::ptr videoDevice, Input::Device::ptr inputDevice);

		public:

			MAKE_SHARED3(System, EngineInfo, Video::Device::ptr, Input::Device::ptr);



			/**
			 * Get the name of this system.
			 */
			QString name() const;

			/**
			 * Update this system.
			 */
			void update();



			/**
			 * Load the given style document and given texture and then tries
			 * to use them as the current style and atlas.
			 * Performs a role-back in case anything goes wrong.
	 
			 * @throws exception            in case loading the style or texture didn't work.
			 * @throws critical_exception   in case the roleback didn't work
			 */
			void loadStyle(QString style, QString texture);

			/**
			 * Sets the given style document and texture as the new style and texture atlas.
			 */
			void setStyle(BasicStyleDefinition::ptr style, Video::Texture::ptr texture);

			/**
			 * Test if wireframe rendering is enabled or disabled.
			 */
			bool wireframe() const;

			/**
			 * Enable/Disable additional wireframe rendering of the UI.
			 */
			void setWireframe(bool b);

			/**
			 * Get the desktop to add/remove widgets.
			 */
			Desktop::ptr desktop() const;

			/**
			 * Get the system state (to modify the modal widget for example).
			 */
			SystemState::ptr state() const;

			/**
			 * Must be called manually because there is no way to capture
			 * WM_CHAR messages through keyboard/window hooks.
			 */
			void processInput(QChar c);

		private:

			void render();

			/**
			 * Resizes the Desktop and places all widgets accordingly.
			 */
			void resize(uint32 width, uint32 height);

			Video::RenderNode::ptr createNormalNode() const;
			Video::RenderNode::ptr createWireframeNode() const;
			Video::Effect::ptr createEffect() const;
			BasicStyleDefinition::ptr createStyle(QString fname) const;
			Video::Texture::ptr createTexture(QString fname) const;

			void changeStyle(BasicStyleDefinition::ptr style, Video::Texture::ptr texture);

		private:

			logger::stream::ptr         m_logger;

			/// Both the video device and input device
			/// are needed to get the UI working
			Video::Device::ptr          m_videoDevice;
			Input::Device::ptr          m_inputDevice;

			/// That is the mesh that contains the entire
			/// visible GUI on screen
			Video::Mesh::ptr            m_mesh;

			/// This is an intermediate buffer for the quads
			/// that will be transfered to the mesh
			Quads                       m_quads;

			/// This is the only shader that is needed to render the UI
			Video::Effect::ptr          m_effect;


			/// This is the style, that is used for the Ui
			BasicStyleDefinition::ptr   m_style;
			/// The texture comes along with the style
			Video::Texture::ptr         m_texture;

			/// The desktop is the most basic widget that spans over the entire screen
			Desktop::ptr                m_desktop;
			Widget::ptr                 m_modalWidget;
			SystemState::ptr            m_state;


			/// Whether or not to draw the UI wireframed
			bool                        m_wireframe;

			Video::RenderNode::ptr      m_normalNode;
			Video::RenderNode::ptr      m_wireframeNode;

			/// Rendering "temporaries"
			GuiVertices                 m_vertices;
			Indices16                   m_indices16;
			Indices32                   m_indices32;
		};
		///////////////////////////////////////////////////////////////////////////////////////////
	}
	///////////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////////////////////////
